package com.wolfsea.launcherdemo
import android.content.Context
import android.graphics.Rect
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.ViewGroup
import androidx.core.view.get

/**
 *@desc  TopContentViewGroup
 *@author liuliheng
 *@time 2023/1/30  16:35
 **/
class TopContentViewGroup @JvmOverloads constructor(
    context: Context,
    attributeSet: AttributeSet? = null
) : ViewGroup(context, attributeSet) {

    private var downX = 0
    private var downY = 0
    private var flagDownX = 0
    private var flagDownY = 0
    private var totalTopCenterMovedY = 0
    private var totalBottomMovedY = 0
    private var totalBottomMovedYShadow = 0

    private var maxTotalTopCenterMovedY = 0

    private var canTopCenterMove = false

    private val totalBottomMovedValue = context.resources.getDimension(R.dimen.dp_100).toInt()

    private val bottomRect by lazy {
        Rect()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        for (i in 0.until(childCount)) {
            val child = get(i)
            measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0)
        }
        setMeasuredDimension(
            MeasureSpec.getSize(widthMeasureSpec) - paddingStart - paddingEnd,
            MeasureSpec.getSize(heightMeasureSpec) - paddingTop - paddingBottom
        )
    }

    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        var borderValue = 0
        maxTotalTopCenterMovedY = 0
        for (i in 0.until(childCount)) {
            val child = get(i)
            val childMeasuredWith = child.measuredWidth
            val childMeasuredHeight = child.measuredHeight
            val layoutParams = child.layoutParams as MarginLayoutParams
            when (i) {
                0 -> {
                    child.layout(
                        layoutParams.leftMargin,
                        layoutParams.topMargin + totalTopCenterMovedY,
                        layoutParams.leftMargin + childMeasuredWith,
                        layoutParams.topMargin + childMeasuredHeight + totalTopCenterMovedY
                    )
                    borderValue += layoutParams.topMargin + childMeasuredHeight
                    maxTotalTopCenterMovedY += layoutParams.topMargin + childMeasuredHeight
                }
                1 -> {
                    child.layout(
                        layoutParams.leftMargin,
                        layoutParams.topMargin + borderValue + totalTopCenterMovedY,
                        layoutParams.leftMargin + childMeasuredWith,
                        layoutParams.topMargin + borderValue + childMeasuredHeight + totalTopCenterMovedY
                    )
                    maxTotalTopCenterMovedY += layoutParams.topMargin + childMeasuredHeight
                }
                else -> {
                    child.layout(
                        layoutParams.leftMargin,
                        layoutParams.topMargin + measuredHeight - childMeasuredHeight + totalBottomMovedY,
                        layoutParams.leftMargin + childMeasuredWith,
                        layoutParams.topMargin + measuredHeight + totalBottomMovedY
                    )

                    maxTotalTopCenterMovedY += layoutParams.topMargin + childMeasuredHeight - totalBottomMovedValue

                    bottomRect.set(
                        layoutParams.leftMargin,
                        layoutParams.topMargin + measuredHeight - childMeasuredHeight + totalBottomMovedY,
                        layoutParams.leftMargin + childMeasuredWith,
                        layoutParams.topMargin + measuredHeight + totalBottomMovedY
                    )
                }
            }
        }

        maxTotalTopCenterMovedY -= measuredHeight
    }

    override fun generateLayoutParams(attrs: AttributeSet?): LayoutParams {
        return MarginLayoutParams(context, attrs)
    }

    override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
        parent.requestDisallowInterceptTouchEvent(true)
        return super.dispatchTouchEvent(ev)
    }

    override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
        when (ev?.action) {
            MotionEvent.ACTION_DOWN -> {
                Log.d(TAG, "onInterceptTouchEvent--ACTION_DOWN")
                downX = ev.x.toInt()
                downY = ev.y.toInt()
                if (bottomRect.contains(downX, downY)) {
                    return (get(2) as ViewGroup).onInterceptTouchEvent(ev)
                }
            }
            MotionEvent.ACTION_MOVE -> {
                Log.d(TAG, "onInterceptTouchEvent--ACTION_MOVE")
                val moveX = ev.x.toInt()
                val diffX = moveX - downX
                val moveY = ev.y.toInt()
                val diffY = moveY - downY
                val condition = Math.abs(diffY) > Math.abs(diffX) && Math.abs(diffY) > BaseConstant.MIN_SLIDE_DISTANCE
                return if (condition) {
                    downX = moveX
                    downY = moveY
                    true
                } else {
                    downX = moveX
                    downY = moveY
                    super.onInterceptTouchEvent(ev)
                }
            }
            MotionEvent.ACTION_UP -> {
                Log.d(TAG, "onInterceptTouchEvent--ACTION_UP")
            }
        }
        return super.onInterceptTouchEvent(ev)
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        performClick()
        when (event?.action) {
            MotionEvent.ACTION_DOWN -> {
                flagDownX = event.x.toInt()
                flagDownY = event.y.toInt()
                downX = flagDownX
                downY = flagDownY
            }
            MotionEvent.ACTION_MOVE -> {
                val moveX = event.x.toInt()
                val diffX = moveX - downX
                val moveY = event.y.toInt()
                val diffY = moveY - downY
                val condition = Math.abs(diffY) > Math.abs(diffX)
                if (condition) {
                    if (diffY > 0) {
                        if (totalBottomMovedYShadow == 0) {
                            totalBottomMovedY += diffY
                            totalBottomMovedY = Math.min(totalBottomMovedY, totalBottomMovedValue)
                            totalTopCenterMovedY = 0
                        } else {
                            if (canTopCenterMove) {
                                totalTopCenterMovedY += diffY
                                totalTopCenterMovedY = Math.min(totalTopCenterMovedY, 0)
                            }
                        }
                        requestLayout()
                    } else {
                        if (totalBottomMovedYShadow == 0) {
                            if (totalBottomMovedY == 0) {
                                parent.requestDisallowInterceptTouchEvent(false)
                            } else {
                                totalBottomMovedY += diffY
                                totalBottomMovedY = Math.max(totalBottomMovedY, 0)
                                requestLayout()
                            }
                        } else {
                            if (canTopCenterMove) {
                                totalTopCenterMovedY += diffY
                                totalTopCenterMovedY =
                                    Math.max(totalTopCenterMovedY, -maxTotalTopCenterMovedY)
                                requestLayout()
                            }
                        }
                    }
                }
                downX = moveX
                downY = moveY
            }
            MotionEvent.ACTION_UP -> {
                canTopCenterMove = totalBottomMovedValue != 0
                val upX = event.x.toInt()
                val upY = event.y.toInt()
                val diffX = upX - flagDownX
                val diffY = upY - flagDownY
                val condition = Math.abs(diffY) > Math.abs(diffX)
                if (condition) {
                    if (totalBottomMovedY > totalBottomMovedValue / 6) {
                        totalBottomMovedY = totalBottomMovedValue
                        totalBottomMovedYShadow = totalBottomMovedValue
                    } else {
                        totalBottomMovedY = 0
                        totalBottomMovedYShadow = 0
                    }
                    requestLayout()
                }
            }
        }
        return true
    }

    override fun performClick(): Boolean {
        return super.performClick()
    }

    fun moveMoveLayout(upToBottom: Boolean, moveValue: Int) {
        totalBottomMovedY += moveValue
        totalBottomMovedY = if (upToBottom) {
            Math.min(totalBottomMovedY, totalBottomMovedValue)
        } else {
            Math.max(totalBottomMovedY, 0)
        }
        requestLayout()
    }

    fun upMoveLayout(upToBottom: Boolean) {
        if (upToBottom) {
            if (Math.abs(totalBottomMovedY) > totalBottomMovedValue / 6) {
                totalBottomMovedY = totalBottomMovedValue
                totalBottomMovedYShadow = totalBottomMovedValue
            } else {
                totalBottomMovedY = 0
                totalBottomMovedYShadow = 0

                totalTopCenterMovedY = 0
            }
        } else {
            if (Math.abs(totalBottomMovedY) > totalBottomMovedValue * 5 / 6) {
                totalBottomMovedY = totalBottomMovedValue
                totalBottomMovedYShadow = totalBottomMovedValue
            } else {
                totalBottomMovedY = 0
                totalBottomMovedYShadow = 0

                totalTopCenterMovedY = 0
            }
        }
        requestLayout()
    }

    fun hideContentView(): Boolean = totalBottomMovedY == 0

    companion object {
        const val TAG = "TopContentViewGroup"
    }

}